package com.springcloud.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.springcloud.hystrix.MyHystrixCommand;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;

/**
 * 服务消费者可以返回JSON或视图页面
 * 我们使用@RestController仅仅是方便测试
 */
@RestController
public class ConsumerController {

    @Resource
    private RestTemplate restTemplate;

    /**
     * @HystrixCommand 这个注解用户标记当前方法支持Hystrix的服务熔断,如果当前方法抛出异常或执行超时就会触发服务熔断
     *  属性
     *    fallbackMethod 用于指定一个本地的自定义服务降级方法,如果当前方法触发服务熔断后将自动调用这个方法利用这个方法的返回值
     *    来替代当前控制器方法的真是返回内容
     */
    @HystrixCommand( fallbackMethod = "error")
    @RequestMapping("/test01")
    public Object test01(){
        String url="http://06-hysrtrix-provider/test01";
        ResponseEntity<String> responseEntity= restTemplate.getForEntity(url,String.class);
        String body=responseEntity.getBody();
        return "服务消费者-----"+body;
    }


    /**
     * @HystrixCommand 这个注解用户标记当前方法支持Hystrix的服务熔断,如果当前方法抛出异常或执行超时就会触发服务熔断
     *  属性
     *    commandProperties 用于指定熔断器的属性 取值为@HystrixProperty 数组
     *       @HystrixProperty 用于指定熔断器的某个属性设置
     *         属性
     *           name 用于指定熔断器的属性名execution.isolation.thread.timeoutInMilliseconds 为熔断的超时设置
     *           value 用于指定某个熔断器属性的具体值6000表示熔断器的最大等待时间,要求当前方法必须在6000毫秒内完成
     *                否则将触发服务熔断,默认的超时时间为1000毫秒
     */
    @HystrixCommand( fallbackMethod = "error", commandProperties={
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value="4000")})
    @RequestMapping("/test02")
    public Object test02(){
        String url="http://06-hysrtrix-provider/test02";
        ResponseEntity<String> responseEntity= restTemplate.getForEntity(url,String.class);
        String body=responseEntity.getBody();
        return "服务消费者-----"+body;
    }

    /**
     * @HystrixCommand 这个注解用户标记当前方法支持Hystrix的服务熔断,如果当前方法抛出异常或执行超时就会触发服务熔断
     *  属性
     *    ignoreExceptions 异常忽略,如果当前方法抛出了被忽略的异常以后将不会触发服务的熔断,而是将异常信息抛出到
     *                     服务的调用者处
     *   注意:
     *     忽略异常时不建议是使用Throwable.class或Exception.class或RuntimeException.class,因为范围
     *     太大可能会导致所有的异常都不会触发服务熔断
     */
    @HystrixCommand( fallbackMethod = "error",ignoreExceptions = {NullPointerException.class})
    @RequestMapping("/test03")
    public Object test03(){
        String  str=null;
        System.out.println(str.toString());
        String url="http://06-hysrtrix-provider/test02";
        ResponseEntity<String> responseEntity= restTemplate.getForEntity(url,String.class);
        String body=responseEntity.getBody();
        return "服务消费者-----"+body;
    }
    @RequestMapping("/test04")
    public Object test04(){
        String url="http://06-hysrtrix-provider/test01";
        MyHystrixCommand command=new MyHystrixCommand(restTemplate,url);
        //执行自定义熔断器类,,并自动调用run方法如果抛出异常则自动调用getFallback方法
        //返回值为响应数据,可能是真实返回的内容或熔断后的内容
        String result= command.execute();
        return "服务消费者-----"+result;
    }
    /**
     * 服务降级方法,这是一个自定的方法,当某个控制器方法触发服务熔断时将使用这个方法的返回内容来替代控制器的真是返回信息
     * 虽然这个结果不是用户最终期望的结果但是至少好过出现异常或指定超时
     * 参数 throwable为触发服务熔断是的异常信息,所有的服务熔断都会抛出异常,我们应该根据不同的异常信息来返回不同的熔断数据
     * 注意:
     *   1.如果远程服务出现异常则统一返回HttpServerErrorException$InternalServerError异常对象,表示服务器内部错误
     *   2.如果执行超时则抛出HystrixTimeoutException异常
     *   3.如果是当前类中的控制器方法出现异常则会抛出具体的异常信息例如 NullPointerException
     */
    public String  error(Throwable throwable){
        System.out.println(throwable.getClass());
        System.out.println(throwable.getMessage());
        return "触发服务熔断了";
    }
}
